package code.accelerometro2;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Chronometer;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;


import com.androidplot.series.XYSeries;
import com.androidplot.ui.AnchorPosition;
import com.androidplot.ui.widget.Widget;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.XLayoutStyle;
import com.androidplot.xy.XYPlot;
import com.androidplot.xy.LineAndPointRenderer;
import com.androidplot.xy.YLayoutStyle;
import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.SimpleXYSeries.ArrayFormat;


/**
 * La classe  un'activity che consente la lettura dati provenienti dall'accelerometro e il relativo salvataggio in SD attraverso un file txt
 * @author  Oriana Costantino, Silvia Nunnari
 *
 */

public class AccelerometerActivity extends Activity implements SensorEventListener
{
        private TextView txtX;
    private TextView txtY;
    private TextView txtZ;
    private TextView txtCrono;
    // per salvare i dati sull'SD dello smartphone 
    private File sd;
    private File f;
    private String stringX;
    private String stringY;
    private String stringZ;
    private String msg; //conterr la stringa proveniente della MainActivity
    Button blocca;
    Button riavvia;
    Button vediGraf;
    public SensorManager mSensorManager;
    private XYPlot mySimpleXYPlot;
    private SimpleXYSeries xHistorySeries = null;
    private SimpleXYSeries yHistorySeries = null;
    private SimpleXYSeries zHistorySeries = null;
    private static LinkedList<Number> xList;
    private static LinkedList<Number> yList;
    private static LinkedList<Number> zList;
    private static final int LIST_SIZE = 30; // numero di massimo di punti che verranno visualizzati nel grafico realtime
    public static LinkedList<Number> xHistoryFilter;
    public static LinkedList<Number> yHistoryFilter;
    public static LinkedList<Number> zHistoryFilter;

    public Cronometro crono; 
    public static int counter = 0;
    
    private CheckBox checkX;
    private CheckBox checkY;
    private CheckBox checkZ;
    public static boolean xchecked = false;
    public static boolean ychecked = false;
    public static boolean zchecked = false;

    

    @Override
    public void onCreate(Bundle savedInstanceState) {
        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_accelerometer);
        
        //crazione del file txt su SD 
        sd = Environment.getExternalStorageDirectory();
        f = new File(sd, "dati_accelerometro.txt");
           
                Intent intent= getIntent();
                //ottengo i dati proveninienti dall'activity chiamante
                msg =  intent.getStringExtra("sampleData");
                mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
                
                creaGrafico();
                avviaAccelerometro();
                crono = new Cronometro(); //avvio cronometro
                
                //creo una nuova variabile che sar leggibile all'activity chiamante al ritorno della intent
                intent.putExtra("returnedData", msg);
                Toast.makeText(AccelerometerActivity.this, msg+ " e' la frequenza selezionata", Toast.LENGTH_LONG).show();
                setResult(RESULT_OK, intent);
                
              //implementazione del button stop che consentir di fermare la lettura dei dai provenienti dall'accelerometro
                blocca.setEnabled(true);
                blocca.setOnClickListener(new OnClickListener() {
                   
                     public void onClick(View v)  {
                        mSensorManager.unregisterListener(AccelerometerActivity.this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) );
                        blocca.setEnabled(false);
                        riavvia.setEnabled(true);
                        crono.ferma();
                        
                     }
                }  );
                
                //implementazione del button riavvia che consentira' di effettuare una nuova misurazione
                riavvia.setEnabled(false);
                riavvia.setOnClickListener(new OnClickListener() {
                     public void onClick(View v)  {
                        Toast.makeText(AccelerometerActivity.this, msg+ " e' la frequenza selezionata", Toast.LENGTH_LONG).show();
                        blocca.setEnabled(true);
                        riavvia.setEnabled(false);
                        avviaAccelerometro();
                        crono.avanzaDaCapo();
                        resetListe();
                     }
                 }  );
                
                //implementazione del button GRAFICO
                vediGraf.setOnClickListener(new OnClickListener() {
                        Intent intent= getIntent();
                        public void onClick(View v)  {
                                mSensorManager.unregisterListener(AccelerometerActivity.this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) );
                                crono.ferma();
                                // verifica del checkbox selezionato
                                xchecked = checkX.isChecked();
                                ychecked = checkY.isChecked();
                                zchecked = checkZ.isChecked();
                                
                                //se non  stato selezionato nessun checkbox non passa all'activity successiva e spunta un messaggio di notifica
                                if(xchecked || ychecked || zchecked){
                                     intent = new Intent(AccelerometerActivity.this, Grafico.class);
                                startActivityForResult(intent, 1);
                                }
                                else 
                                     Toast.makeText(AccelerometerActivity.this, "Seleziona almeno un asse!", Toast.LENGTH_LONG).show();
                    }
                        
                }  );
                
                                
    } //fine onCreate  
  
    private void creaGrafico(){
        xList = new LinkedList<Number>();
        yList = new LinkedList<Number>();
        zList = new LinkedList<Number>();
        
        xHistoryFilter = new LinkedList<Number>();
        yHistoryFilter = new LinkedList<Number>();
        zHistoryFilter = new LinkedList<Number>();
        
        xHistorySeries = new SimpleXYSeries("AsseX");
        yHistorySeries = new SimpleXYSeries("AsseY");
        zHistorySeries = new SimpleXYSeries("AsseZ");
        
        mySimpleXYPlot = (XYPlot) findViewById(R.id.myPlot);
  
        // aggiunta delle serie che rappresentano l'andamento dei dati dell'accelerometro rispettivamente lungo gli assi X Y e Z
        mySimpleXYPlot.addSeries(xHistorySeries,  LineAndPointRenderer.class, new LineAndPointFormatter(Color.rgb(100, 100, 200), Color.BLACK, null));
        mySimpleXYPlot.addSeries(yHistorySeries,  LineAndPointRenderer.class, new LineAndPointFormatter(Color.rgb(100, 200, 100), Color.BLACK, null));
        mySimpleXYPlot.addSeries(zHistorySeries,  LineAndPointRenderer.class, new LineAndPointFormatter(Color.rgb(200, 100, 100), Color.BLACK, null));
        
        mySimpleXYPlot.setRangeBoundaries(-25, 25, BoundaryMode.AUTO) ;
        mySimpleXYPlot.setDomainBoundaries(0, 10000, BoundaryMode.AUTO);
        
        // set del dominio del range e delle label degli assi
        mySimpleXYPlot.setDomainStepValue(10);
        mySimpleXYPlot.setTicksPerRangeLabel(3);
        mySimpleXYPlot.setDomainLabel("Tempo");
        mySimpleXYPlot.getDomainLabelWidget().pack();
        mySimpleXYPlot.setRangeLabel("Accelerazione");
        mySimpleXYPlot.getRangeLabelWidget().pack();
        mySimpleXYPlot.disableAllMarkup(); 
    }


/**
 * Metodo che permette la lettura dei dati dell'accelerometro in base alla frequenza selezionata nella MainActivity
 */
   private void avviaAccelerometro(){
           if(msg.equals("10 50 (Hz)")) {
           mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) ,
                           SensorManager.SENSOR_DELAY_NORMAL);
           }
   
           if(msg.equals("50 100 (Hz)")) {
           mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) ,
                           SensorManager.SENSOR_DELAY_UI);
           }
   
           if(msg.equals("100 150 (Hz)")) {
           mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) ,
                           SensorManager.SENSOR_DELAY_GAME);
           }
           if(msg.equals("150 200 (Hz)")) {
           mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) ,
                           SensorManager.SENSOR_DELAY_FASTEST);                                        
           }
           initComponents();

   }
   
 /**
  * Metodo che permette l'inizializzazione dei componenti   
  */
   
    private void initComponents() {
        blocca = (Button) findViewById(R.id.button1); //inizializzazione button blocca con Stop (button1)
        riavvia = (Button) findViewById(R.id.button2); 
        vediGraf = (Button) findViewById(R.id.button3);
        txtX = (TextView) findViewById(R.id.txtX);
        txtY = (TextView) findViewById(R.id.txtY);
        txtZ = (TextView) findViewById(R.id.txtZ);
        txtCrono = (TextView) findViewById(R.id.textCrono);
        checkX = (CheckBox) findViewById(R.id.checkBoxX);
        checkY = (CheckBox) findViewById(R.id.checkBoxY);
        checkZ = (CheckBox) findViewById(R.id.checkBoxZ);
        
   }

    
        
 /**
 * Metodo che monitora quando il sensore (accelerometro) genera un evento
 * i dati letti verranno salvati in un file di testo nell'SD ed inseriti nelle strutture dati necessarie per la visualizzazione del grafico
 */
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                        
            // Tutti i valori sono misurati nell'unit del SI (m/s^2) .
            // Accelerazione misurata lungo l'asse X
                Float tmp = event.values[0];
                double n = troncaCifreDec(tmp, 2);
            txtX.setText("X: " + Double.toString(n));
            write((stringX = ((String)txtX.getText()).concat(" tempo in ms: "+ ((double) crono.leggi()) /1000 + "\n")));
             
            // Accelerazione misurata lungo l'asse Y
            Float tmp1 = event.values[1];
                double n1 = troncaCifreDec(tmp1, 2);
                txtY.setText("Y: " + Double.toString(n1));
                write((stringY = ((String)txtY.getText()).concat("\n")));
             
            //Accelerazione misurata lungo l'asse Z
            Float tmp2 = event.values[2]; 
                double n2 = troncaCifreDec(tmp2, 2);
            txtZ.setText("Z: " + Double.toString(n2));
            write((stringZ = ((String)txtZ.getText()).concat("\n\n")));
        }
        
        //il cronometro verra' visualizzato in secondi con due numeri dopo la virgola
        double tmp = ((double) crono.leggi()) /1000;
        double troncato = troncaCifreDec (tmp, 2);
        txtCrono.setText("Crono: " + troncato + " s");
        
        
       //ogni volta che viene letto un valore si incrementa un contatore, necessario per il successivo campionamento
                counter++;
       
        //inserisco nella lista un campione ogni 5, questo campionamento consentirà una migliore leggibilità del grafico complessivo 
                if((counter % 5) == 0){
                        xHistoryFilter.addLast(tmp);
                        xHistoryFilter.addLast(event.values[0]);
                        yHistoryFilter.addLast(tmp);
                        yHistoryFilter.addLast(event.values[1]);
                        zHistoryFilter.addLast(tmp);
                        zHistoryFilter.addLast(event.values[2]);
                        Log.i("aggiunto a TOTAL", "AGGIUNTOOOOOOOO");
                }
           
          
        
        // controllo sulla dimensione della lista per la visualizzazione real time
        if (xList.size() > LIST_SIZE) {
            xList.removeFirst(); //rimuove il tempo
            xList.removeFirst(); //rimuove il valore
            yList.removeFirst();
            yList.removeFirst();
            zList.removeFirst();
            zList.removeFirst();
        }
        
        xList.addLast((Number) (crono.leggi()/100)); //precisione al decimo di secondo
        xList.addLast(event.values[0]);
        yList.addLast((Number)(crono.leggi()/100));
        yList.addLast(event.values[1]);
        zList.addLast((Number) (crono.leggi()/100));
        zList.addLast(event.values[2]);
       
        xHistorySeries.setModel(xList, SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED);
        yHistorySeries.setModel(yList, SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED);
        zHistorySeries.setModel(zList, SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED);
        
        mySimpleXYPlot.redraw();
    }  
    
    
    /**
     * Metodo che permette di troncare i valori letti dell'accelerometro alla cifra decimale desiderata
     * @param v
     * @param cifre
     * @return double
     */
    public static double troncaCifreDec(double v, int cifre) {
        double mult = Math.pow(10, cifre);
        return Math.floor(v*mult) / mult;
    }
    
    /**
     * Metodo che consente la scrittura dei dati in un file di testo
     * @param String data (dati da scrivere nel file)
     */
    public void write (String data){
        FileWriter fw = null;
        BufferedWriter bw = null;
        try{
                fw = new FileWriter(f, true);
                bw = new BufferedWriter(fw);
                bw.write(data);
                bw.close();
                fw.close();
            //Toast.makeText(context, "salvato",Toast.LENGTH_SHORT).show();
            }
            catch (IOException e) {      
            e.printStackTrace();
            //Toast.makeText(context, "Non salvato",Toast.LENGTH_SHORT).show();
            }
        }
    
    
    /**
     * Metodo che permette di ripulire le linkedlist.
     */
    public static void resetListe(){
        xHistoryFilter.clear();
        yHistoryFilter.clear();
        zHistoryFilter.clear();
        xList.clear();
        yList.clear();
        zList.clear();
   }
   
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_accelerometer, menu);
        return true;
    }

      
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
                
    }
    
    
}